﻿using System;
using System.IO;
using System.Text;

namespace ZenWplExporter
{
	/// <summary>
	/// Locates files on Zen device
	/// </summary>
	internal static class ZenFileLocator
	{
		/// <summary>
		/// Locates the file on ZEN device and returns short (DOS8.3) file name and path.
		/// </summary>
		/// <param name="rootPath">Full path to a ZEN root music folder.</param>
		/// <param name="artist">The file artist.</param>
		/// <param name="album">The album of the file.</param>
		/// <param name="name">The name of the file.</param>
		/// <returns>Zen file name</returns>
		public static string LocateFile(string rootPath, string artist, string album, string name)
		{
			#region Params Check

			if (String.IsNullOrEmpty(rootPath))
			{
				throw new ArgumentNullException("rootPath");
			}
			if (String.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}

			#endregion

			string album2 = String.IsNullOrEmpty(album)
			                	? "Unknown Album"
			                	: ReplaceInvalidlChars(album);

			string artist2 = String.IsNullOrEmpty(artist)
			                 	? "Unknown"
			                 	: ReplaceInvalidlChars(artist.Contains("/") ? artist.Substring(0, artist.IndexOf("/")) : artist);

			string path = Path.Combine(Path.Combine(Path.Combine(rootPath, artist2), album2), name);

			return GetShortName(path);
		}

		/// <summary>
		/// Locates the file on ZEN device and returns short (DOS8.3) file name and path.
		/// </summary>
		/// <param name="rootPath">Full path to root ZEN music folder.</param>
		/// <param name="name">The name of the file.</param>
		/// <returns>Zen file name</returns>
		public static string LocateFile(string rootPath, string name)
		{
			#region Params Check

			if (String.IsNullOrEmpty(rootPath))
			{
				throw new ArgumentNullException("rootPath");
			}
			if (String.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}

			#endregion

			var path = Path.Combine(rootPath, name);
			return GetShortName(path);
		}

		private static string GetShortName(string longPath)
		{
			if (File.Exists(longPath))
			{
				var shortPathBuilder = new StringBuilder(255);

				int hresult = NativeMethods.GetShortPathName(longPath, shortPathBuilder, shortPathBuilder.Capacity);
				if (hresult == 0)
				{
					throw new InvalidOperationException("Exception retrieving short path name.");
				}

				string shortPath = shortPathBuilder.ToString();

				if (!IsShortName(shortPath)) // Ensure basic short-part rules
				{
					throw new InvalidOperationException(
						String.Format(
							"File [{0}] on your ZEN device does not have short file name (OS reports [{1}]). Please re-connect your ZEN device and try again.",
							longPath,
							shortPath));
				}

				return shortPath;
			}

			throw new FileNotFoundException("Cannot locate file on ZEN device.", longPath);
		}

		private static bool IsShortName(string path)
		{
			string[] parts = path.Split(Path.DirectorySeparatorChar);
			foreach (string part in parts)
			{
				for (int i = 0; i < part.Length; i++)
				{
					if (i > 11 || part[i].Equals(" "))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static string ReplaceInvalidlChars(string value)
		{
			foreach (char c in Path.GetInvalidFileNameChars())
			{
				if (value.IndexOf(c) > -1)
				{
					value = value.Replace(c, ' ');
				}
			}

			return value;
		}
	}
}